home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Decision Cube / mxdb.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  70KB  |  2,418 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {       Borland Delphi Visual Component Library         }
  4. {                                                       }
  5. {       Copyright (c) 1997,99 Inprise Corporation       }
  6. {                                                       }
  7. {*******************************************************}
  8.  
  9. unit mxDB;
  10.  
  11. interface
  12.  
  13. uses
  14.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  15.   Menus, Bde, DB, DBTables, mxArrays, mxStore, mxConsts, mxcommon, mxtables,
  16.   mxqparse, mxqedcom;
  17.  
  18. type
  19.   EArrayError = class(Exception);
  20.   EDimIndexError = class(Exception);
  21.  
  22.   TDimGroup = (dgRow, dgCol, dgSum, dgPage, dgNone);
  23.  
  24.   TRowStates = (rcNextOpen, rcPrevOpen, rcNextClosed, rcPrevClosed);
  25.   TRowState = set of TRowStates;
  26.  
  27.   TDimState = (dmClosed, dmOpen, dmDrilled, dmPaged, dmNone);
  28.  
  29.   TDecisionControlType = (xtCheck, xtRadio, xtRadioEx);
  30.  
  31.   TIArray = class
  32.   private
  33.     FLimit: Integer;
  34.     FAutoIncr: Boolean;
  35.     FElements: Pointer;
  36.     FBlockSize: Integer;
  37.     FCapacity: Integer;
  38.     procedure Alloc(ALimit: Integer);
  39.     procedure Realloc(ALimit: Integer);
  40.   protected
  41.     function GetItem(Index: Integer): Integer;
  42.     procedure SetItem(Index: Integer; Value: Integer);
  43.   public
  44.     constructor Create(ALimit: Integer; ABlockSize: Integer);
  45.     destructor Destroy; override;
  46.     procedure Assign(Value: TIArray);
  47.     procedure InsertAt(Index: Integer; Value: Integer);
  48.     function RemoveItem(Index: Integer): Integer;                
  49.     property AutoSize: Boolean read FAutoIncr write FAutoIncr;
  50.     property Limit: Integer read FLimit;
  51.     property Items[Index: Integer]: Integer read GetItem write SetItem; default;  
  52.  
  53.   end;
  54.  
  55.   PArrayInt = ^TArrayInt;
  56.   TArrayInt = array[0..MaxInt div 8] of Integer;
  57.  
  58.   TDimInfo = Record
  59.     iState: TDimState;
  60.     iValue: Integer;
  61.     iIndex: Integer;
  62.     iActiveIndex: Integer;
  63.     iRowState: TRowState;
  64.     iGroup: TDimGroup;
  65.   end;
  66.  
  67.   TDimRange = Record
  68.     First: Integer;
  69.     Last: Integer;
  70.   end;
  71.  
  72.   TBigStr = array[0..100000] of Char;
  73.   PDimInfo = ^TDimInfo;
  74.   TArrayDimInfo = array[0..999] of TDimInfo;
  75.   PArrayDimInfo = ^TArrayDimInfo;
  76.  
  77.   TDimInfoArray = class
  78.   private
  79.     FLimit: Integer;
  80.     FElements: pointer;
  81.     AllXDim: TIArray;
  82.     FDimNames: TStringList;
  83.   protected
  84.     function  GetItem(Index: Integer): PDimInfo;
  85.     function Find(Name: string; var pos: Integer): Boolean;
  86.   public
  87.     constructor Create(ALimit: Integer);
  88.     destructor Destroy; override;
  89.     procedure Assign( Value: TDimInfoArray);
  90.     function GetGroupItem(Group: TDimGroup; Index: Integer; bOpen: Boolean): PDimInfo;
  91.     function GetGroupIndex(Group: TDimGroup; Index: Integer; bOpen: Boolean): Integer;
  92.     function GetGroupSize(Group: TDimGroup; bOpen: Boolean): Integer;
  93.     function GetGroupArray(Group: TDimGroup; bOpen: Boolean): TIArray;
  94.     function IsEqual( Value: TDimInfoArray): Boolean;
  95.     property Limit: Integer read FLimit;
  96.     property Items[Index: Integer]: PDimInfo read GetItem; default;
  97.   end;
  98.  
  99.   TPivotState = class
  100.   protected
  101.     procedure Assign(Value: TPivotState);
  102.     function IsEqual(Value: TPivotState): Boolean;
  103.   public
  104.     FDims: Integer;
  105.     FSums: Integer;
  106.     FCurrentSum: Integer;
  107.     FRowSubs: Boolean;
  108.     FColSubs: Boolean;
  109.     FRowSparse: Boolean;                    
  110.     FColSparse: Boolean;
  111.     DimInfo: TDimInfoArray;
  112.     constructor Create;
  113.     destructor Destroy; override;
  114.   end;
  115.  
  116.  
  117.   TDecisionCube = class;
  118.   TDecisionSource = class;
  119.   TDecisionDataEvent = (xeStateChanged, xeSummaryChanged, xePivot, xeNewMetaData, xeSourceChange);
  120.  
  121.  
  122.   TDecisionDataLink = class(TPersistent)
  123.   private
  124.   protected
  125.     FDecisionSource: TDecisionSource;
  126.     FBlocked: Boolean;
  127.     procedure SetDecisionSource(source: TDecisionSource);
  128.     procedure DecisionDataEvent(Event: TDecisionDataEvent); virtual;
  129.   public
  130.     constructor Create;
  131.     destructor Destroy; override;
  132.     property DecisionSource: TDecisionSource read FDecisionSource write SetDecisionSource;
  133.   end;
  134.  
  135.   TDecisionSource = class(TComponent)
  136.   private
  137.     FChangeCount: Integer;
  138.     FState: TCubeState;
  139.     bActivated: Boolean;
  140.     FBlocked: Boolean;
  141.     FDecisionCube: TDecisionCube;
  142.     FControlType: TDecisionControlType;
  143.     FDecisionDataLinks: TList;
  144.     FSavePivotState: TPivotState;
  145.     FData: TPivotState;
  146.     RowLookup: TTwoDimArray;
  147.     ColLookup: TTwoDimArray;
  148.     FRowMax: Integer;
  149.     FColMax: Integer;                            
  150.     FActiveRows: Integer;
  151.     FActiveCols: Integer;
  152.     FAllRows: Integer;
  153.     FAllPages: Integer;
  154.     FAllCols: Integer;
  155.     procedure SetUpData;
  156.     procedure RebuildPivotState;
  157.     procedure BuildLookups;
  158.     function GetReady: Boolean;
  159.     procedure AddDatalink (link: TDecisionDatalink);
  160.     procedure RemoveDatalink (link: TDecisionDatalink);
  161.     procedure NotifyDataLinks(Event: TDecisionDataEvent);
  162.     procedure ReadDimCount(Reader: TReader);
  163.     procedure WriteDimCount(Writer: TWriter);
  164.     procedure ReadSumCount(Reader: TReader);
  165.     procedure WriteSumCount(Writer: TWriter);
  166.     procedure ReadCurrentSum(Reader: TReader);
  167.     procedure WriteCurrentSum(Writer: TWriter);
  168.     procedure ReadRowSparse(Reader: TReader);
  169.     procedure WriteRowSparse(Writer: TWriter);
  170.     procedure ReadColSparse(Reader: TReader);
  171.     procedure WriteColSparse(Writer: TWriter);
  172.     procedure ReadDimInfo(Reader: TReader);
  173.     procedure WriteDimInfo(Writer: TWriter);
  174.     function GetExampleRepCount(dimGroup: TDimGroup; level: Integer): Integer;
  175.     procedure DrillValue(iDim: Integer; ValueIndex: Integer);
  176.     procedure DecisionDataEvent(Event: TDecisionDataEvent);
  177.     procedure EnforceConstraints(dimGroup: TDimGroup; PreserveIndex: Integer);
  178.     function GetRowSparsing: Boolean;
  179.     function GetColSparsing: Boolean;
  180.     procedure SetRowSparsing(Value: Boolean);
  181.     procedure SetColSparsing(Value: Boolean);
  182.     function GetDecisionCube: TDecisionCube;
  183.     procedure SetDecisionCube(Value: TDecisionCube);
  184.     function GetDims: Integer;
  185.     function GetSums: Integer;
  186.     function GetCurrentSum: Integer;
  187.     procedure ProcessPivotState(FState: TPivotState);
  188.     procedure FetchPivotState (var FState: TPivotState); virtual;
  189.     procedure StorePivotState(FState: TPivotState); virtual;
  190.     procedure BeginChange; virtual;
  191.     procedure EndChange(event: TDecisionDataEvent); virtual;
  192.   protected
  193.     procedure SetDimGroup(iDim: Integer; Group: TDimGroup; Index: Integer; bOpen: Boolean);
  194.     procedure SetDimState(iDim: Integer; State: TDimState; ValueIndex: Integer);
  195.   public
  196.     FOnBeforePivot: TNotifyEvent;
  197.     FOnAfterPivot: TNotifyEvent;
  198.     FOnStateChange: TNotifyEvent;
  199.     FOnNewDimensions: TNotifyEvent;
  200.     FOnLayoutChange: TNotifyEvent;
  201.     FonSummaryChange: TNotifyEvent;
  202.     constructor Create( AOwner: TComponent ); override;
  203.     destructor Destroy; override;
  204.     procedure DefineProperties(Filer: TFiler); override;
  205.     { Meta data and data fetching }
  206.     function GetMemberAsString(iDim: Integer; ValueIndex: Integer): String;
  207.     function GetMemberAsVariant(iDim: Integer; ValueIndex: Integer): Variant;
  208.     function GetDimensionName(iDim: Integer): String;
  209.     function GetDimensionMemberCount(iDim: Integer): Integer;
  210.     function GetSummaryName(iSum: Integer): String;
  211.     procedure SetCurrentSummary(Value: Integer);
  212.     { Graph specific data fetching }
  213.     function Get2DDataAsVariant(iDimA, iDimB: Integer; aValueIndex, bValueIndex:Integer): Variant;
  214.     { Grid specific data fetching }
  215.     function GetDataAsString(ARow, ACol:Integer; var SubLevel: Integer): String;
  216.     function GetDataAsVariant(Arow, ACol: Integer; var SubLevel: Integer): Variant;
  217.     function GetValueIndex(dimGroup: TDimGroup; Index: Integer; Cell: Integer; var isBreak: Boolean; var isSum: Boolean) : Integer;
  218.     function GetValueArray(ACol, ARow: Integer; var ValueArray: TSmallIntArray): Boolean;
  219.     function GetGroupExtent(dimGroup: TDimGroup; Index: Integer; Cell: Integer): TDimRange;
  220.     { Active or Inactive Row/Col relative pivoting functions }
  221.     function GetActiveDim(dimGroup: TDimGroup; index: Integer; bOpen: Boolean): Integer;
  222.     procedure OpenDimIndexRight(dimGroup: TDimGroup; Index: Integer; bOpen: Boolean);
  223.     procedure CloseDimIndexRight(dimGroup: TDimGroup; Index: Integer; bOpen: Boolean);
  224.     procedure OpenDimIndexLeft(dimGroup: TDimGroup; Index: Integer; bOpen: Boolean);
  225.     procedure ToggleDimIndex(dimGroup: TDimGroup; Index: Integer; bOpen: Boolean);
  226.     procedure DrillDimIndex(dimGroup: TDimGroup; Index: Integer; ValueIndex: Integer; bOpen:Boolean);
  227.     procedure MoveDimIndexes(SdimGroup, DdimGroup: TDimGroup; SIndex, DIndex: Integer; bOpen:Boolean);
  228.     procedure SwapDimIndexes(SdimGroup, DdimGroup: TDimGroup; SIndex, DIndex: Integer; bOpen:Boolean);
  229.     function GetGroupCount(dimGroup: TDimGroup; bOpen: Boolean):Integer;
  230.     function GetGroup(iDim: Integer):TDimGroup;
  231.     function GetIndex(iDim: Integer; bOpen: Boolean): Integer;
  232.     function GetState(iDim: Integer): TDimState;
  233.     function GetValue(iDim: Integer): Integer;
  234.     function GetRowState(iDim: Integer): TRowState;
  235.     property Ready: Boolean read GetReady;
  236.     { pivot State Information } 
  237.     property nDims: Integer read GetDims;
  238.     property nSums: Integer read GetSums;
  239.     property nRowDims: Integer read FAllRows;
  240.     property nColDims: Integer read FAllCols;
  241.     property nOpenRowDims: Integer read FActiveRows;
  242.     property nOpenColDims: Integer read FActiveCols;
  243.     property nDataRows: Integer read FRowMax;
  244.     property nDataCols: Integer read FColMax;
  245.     property CurrentSum: Integer read GetCurrentSum;
  246.   published
  247.     property DecisionCube: TDecisionCube read GetDecisionCube write SetDecisionCube;
  248.     property ControlType: TDecisionControlType read FControlType write FControlType;
  249.     property Name;
  250.     property SparseRows: Boolean read GetRowSparsing write SetRowSparsing;
  251.     property SparseCols: Boolean read GetColSparsing write SetColSparsing;
  252.     property OnStateChange: TNotifyEvent read FOnStateChange write FOnStateChange;
  253.     property OnNewDimensions: TNotifyEvent read FOnNewDimensions write FOnNewDimensions;
  254.     property OnLayoutChange: TNotifyEvent read FOnLayoutChange write FOnLayoutChange;
  255.     property OnSummaryChange: TNotifyEvent read FOnSummaryChange write FOnSummaryChange;
  256.     property OnBeforePivot: TNotifyEvent read FOnBeforePivot write FOnBeforePivot;
  257.     property OnAfterPivot: TNotifyEvent read FOnAfterPivot write FOnAfterPivot;
  258.   end;
  259.  
  260.   TQADecisionSource = class(TDecisionSource);
  261.  
  262.   TDecisionCube = class(TCustomDataStore)
  263.   private
  264.     FDecisionSources: TList;                
  265.     FBlocked: Boolean;
  266.     FState: TCubeState;
  267.     FStreamedActive: Boolean;
  268.     procedure CubeSetActive(Value: Boolean );
  269.     function CubeGetActive: Boolean;
  270.     function GetSparsing: Boolean;
  271.     procedure SetSparsing(Value: Boolean );
  272.     procedure AddDataSource(source: TDecisionSource);
  273.     procedure RemoveDataSource(source: TDecisionSource);
  274.     procedure NotifyDataSources(Event: TDecisionDataEvent);
  275.     function GetAnySQL(ValueArray: TSmallIntArray; SelectList: string; bActive: Boolean; bGrouped: Boolean): string;
  276.     property Sparsing: Boolean read GetSparsing write SetSparsing;
  277.   protected
  278.     function CanDimBeClosed(iMapIndex: Integer): Boolean; override;
  279.     function CanSumBeClosed(iMapIndex: Integer): Boolean; override;
  280.   public
  281.     constructor Create( AOwner: TComponent ); override;
  282.     destructor Destroy; override;
  283.     property DesignState;
  284.     function GetSQL(ValueArray: TSmallIntArray; bActive: Boolean): string;
  285.     function GetDetailSQL(ValueArray: TSmallIntArray; SelectList: string; bActive: Boolean): string;
  286.     procedure ShowCubeDialog;
  287.     procedure StateChanged; override;
  288.     {$IFDEF PDEBUGS}
  289.     procedure ShowSQLDialog(SQL: string);
  290.     procedure ShowQueryDialog;
  291.     {$ENDIF}
  292.     {$IFDEF PROFILE}
  293.     procedure CreateIndexTable(Const Filename: String);
  294.     function GetLogFile: string;
  295.     procedure SetLogFile(fName: string);
  296.     {$ENDIF}
  297.     property Active: Boolean read CubeGetActive write CubeSetActive;
  298.   published
  299.     property DataSet;
  300.     property DimensionMap;
  301.     property ShowProgressDialog;
  302.     property MaxDimensions;
  303.     property MaxSummaries;
  304.     property MaxCells;
  305.     property OnLowCapacity;
  306.     property BeforeOpen;
  307.     property AfterOpen;
  308.     property BeforeClose;
  309.     property AfterClose;
  310.     property OnRefresh;
  311.     {$IFDEF PROFILE}
  312.     property ProfileLogFile: string read GetLogFile write SetLogFile;
  313.     {$ENDIF}
  314.   end;
  315.  
  316. implementation
  317.  
  318. { TDecisionCube }
  319.  
  320. uses Math, mxdcube
  321. {$IFDEF PDEBUGS}
  322.   ,mxdssqry, mxdsql
  323. {$ENDIF};
  324.  
  325.   const
  326.     defDimSize = 20;
  327.  
  328. procedure TDecisionSource.SetDimGroup(iDim: Integer; Group: TDimGroup; Index: Integer; bOpen: Boolean);
  329. var
  330.   aDimInfo: pDImInfo;
  331.   oldIndex: Integer;
  332. begin
  333.   aDimInfo := FData.DimInfo.GetGroupItem(Group, Index, bOpen);
  334.   if (bOpen) then
  335.     oldIndex := aDimInfo.iActiveIndex
  336.   else
  337.     oldIndex := aDimInfo.iIndex;
  338.   MoveDimIndexes(aDimInfo.iGroup, Group, oldIndex, index, bOpen);
  339. end;
  340.  
  341. procedure TDecisionSource.SetDimState(iDim: Integer; State: TDimState; ValueIndex: Integer);
  342. var
  343.   aDimInfo: pDimInfo;
  344. begin
  345.   aDimInfo := FData.DimInfo[iDim];
  346.   if (aDimInfo.iState = State) and (aDimInfo.iValue = ValueIndex) then Exit;
  347.   BeginChange;
  348.   aDimInfo.iState := State;
  349.   if (State = dmDrilled) then
  350.     aDimInfo.iValue := ValueIndex
  351.   else if (State = dmPaged) then
  352.     aDimInfo.iValue := 0
  353.   else aDimInfo.iValue := -1;
  354.   EndChange(xePivot);
  355. end;
  356.  
  357. function TDecisionSOurce.GetGroupCount(dimGroup: TDimGroup; bOpen: Boolean): Integer;
  358. begin
  359.   Result := FData.DimInfo.GetGroupSize(dimGroup, bOpen);
  360. end;
  361.  
  362. function TDecisionSource.GetGroup(iDim: Integer): TDimGroup;
  363. begin
  364.   Result := FData.DimInfo[iDim].iGroup;
  365. end;
  366.  
  367. function TDecisionSource.GetIndex(iDim: Integer; bOpen: Boolean): Integer;
  368. begin
  369.   if bOpen then
  370.     Result := FData.DimInfo[iDim].iActiveIndex
  371.   else
  372.     Result := FData.DimInfo[iDim].iIndex;
  373. end;
  374.  
  375. function TDecisionSource.GetState(iDim: Integer): TDimState;
  376. begin
  377.   Result := FData.DimInfo[iDim].iState;
  378. end;
  379.  
  380. function TDecisionSource.GetRowState(iDim: Integer): TRowState;
  381. begin
  382.   Result := FData.DimInfo[iDim].iRowState;
  383. end;
  384.  
  385. function TDecisionSource.GetValue(iDim: Integer): Integer;
  386. begin
  387.   Result := FData.DimInfo[iDim].iValue;
  388. end;
  389.  
  390. function TDecisionSource.GetDims: Integer;
  391. begin
  392.   Result := FData.FDims;
  393. end;
  394.  
  395. function TDecisionSource.GetSums: Integer;
  396. begin
  397.   Result := FData.FSums;
  398. end;
  399.  
  400. function TDecisionSource.GetCurrentSum: Integer;
  401. begin
  402.   Result := FData.FCurrentSum;
  403. end;
  404.  
  405. constructor TDecisionCube.Create(AOwner: TComponent);
  406. begin
  407.   inherited Create(AOwner);
  408.   FDecisionSources := TList.Create;
  409.   FState := dcInActive;
  410.   FBlocked := False;
  411.   FStreamedActive := False;
  412.   DesignState := dsAllData;
  413.   RCS;
  414. end;
  415.  
  416. destructor TDecisionCube.Destroy;
  417. begin
  418.   while FDecisionSources.Count > 0 do
  419.     TDecisionSource(FDecisionSources.Last).DecisionCube := nil;
  420.   assert(FDecisionSources.count = 0, 'Decision Sources did not free correctly');  //$$$ leave asserts? [adm]
  421.   FDecisionSources.Free;
  422.   inherited Destroy;
  423. end;
  424.  
  425. function TDecisionCube.CanDimBeClosed(iMapIndex: Integer): Boolean;
  426. var
  427.   x, i: Integer;
  428. begin
  429.   Result := False;
  430.   if (iMapIndex < DimensionMap.count) and DimensionMap[iMapIndex].Loaded then
  431.   begin
  432.     x := 0;
  433.     for i := 0 to iMapIndex do
  434.     begin
  435.       if (DimensionMap[i].Loaded) and (DimensionMap[i].DimensionType = dimDimension) then
  436.         x := x + 1;
  437.     end;
  438.     for i := 0 to FDecisionSources.count-1 do
  439.     begin
  440.       with TDecisionSource(FDecisionSources[i]) do
  441.       begin
  442.         if assigned(FData) and assigned(Fdata.DimInfo) and ((x-1) < FData.DimInfo.limit) then
  443.         begin
  444.           if Fdata.DimInfo[x-1].iState <> dmClosed then Exit;
  445.         end;
  446.       end;
  447.     end;
  448.   end;
  449.   Result := True;
  450. end;
  451.  
  452. function TDecisionCube.CanSumBeClosed(iMapIndex: Integer): Boolean;
  453. var
  454.   x, i: Integer;
  455. begin
  456.   Result := False;
  457.   if (iMapIndex < DimensionMap.count) and DimensionMap[iMapIndex].Loaded then
  458.   begin
  459.     x := 0;
  460.     for i := 0 to iMapIndex do
  461.     begin
  462.       if (DimensionMap[i].Loaded) and (DimensionMap[i].DimensionType <> dimDimension) then
  463.         x := x + 1;
  464.     end;
  465.     for i := 0 to FDecisionSources.count-1 do
  466.     begin
  467.       with TDecisionSource(FDecisionSources[i]) do
  468.       begin
  469.         if assigned(FData) and assigned(Fdata.DimInfo) and ((x-1) < FData.DimInfo.limit) then
  470.         begin
  471.           if (FData.FCurrentSum = x-1) then Exit;
  472.         end;
  473.       end;
  474.     end;
  475.   end;
  476.   Result := True;
  477. end;
  478.  
  479. {$IFDEF PROFILE}
  480. function TDecisionCube.GetLogFile: string;
  481. begin
  482.   Result := DataCache.ProfileLogFile;
  483. end;
  484.  
  485. procedure TDecisionCube.SetLogFile(fName: string);
  486. begin
  487.   DataCache.ProfileLogFile := fName;
  488. end;
  489.  
  490. procedure TDecisionCube.CreateIndexTable(Const Filename: String);
  491. begin
  492.   DataCache.CreateTable(FileName);
  493. end;
  494. {$ENDIF}
  495.  
  496. procedure TDecisionCube.AddDataSource(source: TDecisionSource);
  497. begin
  498.   FDecisionSources.Add(source);
  499.   source.FDecisionCube := self;
  500. end;
  501.  
  502. procedure TDecisionCube.RemoveDataSource(source: TDecisionSource);
  503. begin
  504.   Source.FDecisionCube := nil;
  505.   FDecisionSources.Remove(Source);
  506. end;
  507.  
  508. procedure TDecisionCube.NotifyDataSources(Event: TDecisionDataEvent);
  509. var
  510.   I: Integer;
  511. begin
  512.   for I := FDecisionSources.Count - 1 downto 0 do
  513.     with TDecisionSource(FDecisionSources[I]) do
  514.     begin
  515.       DecisionDataEvent(Event);
  516.     end;
  517. end;
  518.  
  519. procedure TDecisionCube.CubeSetActive(Value: Boolean);
  520. begin
  521.   if (csReading in ComponentState) then
  522.   begin
  523.     FStreamedActive := Value;
  524.     Exit;
  525.   end;
  526.   if (Value <> FStreamedActive) then inherited Active := Value;
  527.   FStreamedActive := inherited Active;
  528. end;
  529.  
  530. function TDecisionCube.CubeGetActive: Boolean;
  531. begin
  532.   if (csReading in ComponentState) then
  533.     Result := FStreamedActive
  534.   else
  535.     Result := inherited Active;
  536. end;
  537.  
  538. procedure TDecisionCube.StateChanged;
  539. var
  540.   iActive, i: Integer;
  541. begin
  542.   if (FState <> State) then
  543.   Begin
  544.     FState := State;
  545.     if FState <> dcInactive then
  546.     begin
  547.       iActive := 0;
  548.       for i := 0 to DimensionMap.Count-1 do
  549.       begin
  550.         if (DimensionMap[i].loaded) and (DimensionMap[i].DimensionType = dimDimension) then
  551.         begin
  552.           DimensionMap[i].ValueCount := GetDimensionMemberCount(iActive);
  553.           iActive := iActive + 1;
  554.         end;
  555.       end;
  556.     end;
  557.     NotifyDataSources(xeStateChanged);
  558.   end;
  559. end;
  560.  
  561. function TDecisionCube.GetSparsing: Boolean;
  562. begin
  563.   Result := DataCache.Sparsing;
  564. end;
  565.  
  566. procedure TDecisionCube.ShowCubeDialog;
  567. var
  568.   aWindow: TDSSCubeEditor;
  569.   x,y: Integer;
  570. begin
  571.   aWindow := TDSSCubeEditor.Create(application);
  572.   try
  573.     if aWindow.SInitialize(nil, self) then
  574.     begin
  575.       x := (Screen.Width - aWindow.Width) div 2;
  576.       y := (Screen.Height - aWindow.Height) div 2;
  577.       if (x < 0) then x := 0;
  578.       if (y < 0) then y := 0;
  579.       aWindow.Left := x;
  580.       aWindow.Top := y;
  581.       aWindow.ShowModal;
  582.     end;
  583.   finally
  584.     aWindow.free;
  585.   end;
  586. end;
  587.  
  588. function TDecisionCube.GetSQL(ValueArray: TSmallIntArray; bActive: Boolean): string;
  589. begin
  590.   Result := GetAnySQL(ValueArray, '', bActive, True);
  591. end;
  592.  
  593. function TDecisionCube.GetDetailSQL(ValueArray: TSmallIntArray; SelectList: string; bActive: Boolean): string;
  594. begin
  595.   Result := GetAnySQL(ValueArray, SelectList, bActive, False);
  596. end;
  597.  
  598. function TDecisionCube.GetAnySQL(ValueArray: TSmallIntArray; SelectList: string;
  599.                                  bActive: Boolean; bGrouped: Boolean): string;
  600. var
  601.   Map: TCubeDims;
  602.   anError: TQueryError;
  603.   vCondition: Variant;
  604.   i,j: Integer;
  605.   qParse: TXTabQuery;
  606.   myDB: TDataBase;
  607.   aPos, count: Integer;
  608.   myQuery: tQuery;
  609.   aString: string;
  610.   bDataSetMatch: Boolean;
  611. begin
  612.   Result := '';
  613.   if not assigned(DataSet) or not(DataSet is TQuery) then Exit;
  614.   myQuery := TQuery(DataSet);
  615.   if not assigned (myQuery.SQL) or (myQuery.SQL.Text = '') then Exit;
  616.   myDB := myQuery.DBSession.OpenDataBase(myQuery.dataBaseName);
  617.   if (myDB = nil) then Exit;
  618.   myDB.connected := True;
  619.   qParse := TXTabQuery.create;
  620.   qParse.canDelete := False;
  621.   Map := TCubeDims.create(self,TCubeDim);
  622.   try
  623.     Map.Assign(DimensionMap);
  624.     qParse.DBHandle := myDB.Handle;
  625.     qParse.SQLString := MyQuery.SQL.Text;
  626.     anError := VerifyRTQuery(myQUery, Map, bDataSetMatch);
  627.     if anError = tqeNotInitialized then
  628.       raise exception.createRes(@SQryNotInitialized);
  629.     { add where clauses for the non-summary members of the valuearray }
  630.     for i := ValueArray.limit-1 downto 0 do
  631.     begin
  632.       if (ValueArray[i] >= 0) and (Map[i].DimensionType = dimDimension) then
  633.       begin
  634.         if (Map[i].BinType in [binYear, binQuarter, binMonth]) then
  635.         begin
  636.           VCondition := Map[i].GetBinValues( GetMemberAsVariant(i, ValueArray[i]));
  637.           qParse.AddWhereOp(Map[i].BaseName,vcondition[0], qnodeGreaterEq);
  638.           qParse.AddWhereOp(Map[i].basename, vCondition[1], qnodeLess);
  639.         end
  640.         else if Map[i].BinType = binSet then
  641.         begin
  642.           VCondition := Map[i].GetBinValues( GetMemberAsVariant(i, ValueArray[i]));
  643.           for j:= VarArrayLowBound(vCondition,1) to VarArrayHighBound(vCondition,1) do
  644.             qParse.AddWhereOp(Map[i].basename, vCondition[j], qnodeEqual);
  645.         end
  646.         else
  647.         begin
  648.           vCondition := GetMemberAsVariant(i, ValueArray[i]);
  649.           qParse.AddWhereOp(Map[i].basename, vCondition, qnodeEqual);
  650.         end;
  651.       end;
  652.     end;
  653.     { Remove non-active summaries and dimensions if bActive is False }
  654.     for i := Map.count-1 downto 0 do
  655.     begin
  656.       if (bActive and (not Map[i].loaded)) or ((not bGrouped) and (Map[i].DimensionType <> dimDimension)) then
  657.       begin
  658.         if Map[i].DerivedFrom < 0 then
  659.           qParse.DeleteProjector(i);
  660.       end;
  661.     end;
  662.     if not bGrouped then
  663.     begin
  664.       qParse.DeleteGroupBys;
  665.       aPos := 1;
  666.       count := 0;
  667.       while (aPos > 0) do
  668.       begin
  669.         aString := NextArg(aPos, SelectList);
  670.         if aPos > 0 then
  671.         begin
  672.           if (Count = 0) and (SelectList = '*') then
  673.             qParse.DeleteDimensions;
  674.           qParse.AddNewItem(aString, dimDimension, count, False, '');
  675.           count := count + 1;
  676.         end;
  677.       end;
  678.     end;
  679.     if bGrouped then qParse.FixupGroupBys;
  680.     Result := qParse.GetDialectSQLString;
  681.   finally
  682.     qParse.free;
  683.     Map.Free;
  684.   end;
  685. end;
  686.  
  687. {$IFDEF PDEBUGS}
  688. procedure TDecisionCube.ShowSQLDialog(SQL: string);
  689. begin
  690.   if not (DataSet is TQuery) then Exit;
  691.   ShowSQLWindow(TQuery(DataSet).DataBaseName,SQL);
  692. end;
  693.  
  694. procedure TDecisionCube.ShowQueryDialog;
  695. var
  696.   aWindow: TDSSQueryEditor;
  697.   x,y: Integer;
  698.   aQuery: TQuery;
  699. begin
  700.   if not assigned(DataSet) or not (DataSet is TQuery) then
  701.     Exit
  702.   else
  703.     aQuery := TQuery(DataSet);
  704.   aWindow := TDSSQueryEditor.Create(application);
  705.   try
  706.     if aWindow.SInitialize(nil, aQuery) then
  707.     begin
  708.       x := (Screen.Width - aWindow.Width) div 2;
  709.       y := (Screen.Height - aWindow.Height) div 2;
  710.       if (x < 0) then x := 0;
  711.       if (y < 0) then y := 0;
  712.       aWindow.Left := x;
  713.       aWindow.Top := y;
  714.       aWindow.ShowModal;
  715.     end;
  716.   finally
  717.     aWindow.free;
  718.   end;
  719. end;
  720.  
  721. {$ENDIF}
  722. procedure TDecisionCube.SetSparsing(Value: Boolean);
  723. begin
  724.   DataCache.Sparsing := Value;
  725. end;
  726.  
  727. { TDecisionSource }
  728.  
  729. constructor TDecisionSource.Create( AOwner: TComponent );
  730. begin
  731.   inherited Create(AOwner);
  732.   FDecisionDataLinks := TList.Create;
  733.   FState := dcInactive;
  734.   FBlocked := False;
  735.   FData := TPivotState.create;
  736.   FSavePivotState := TPivotState.Create;
  737.   SetUpData;
  738.   RCS;
  739. end;
  740.  
  741. destructor TDecisionSource.Destroy;
  742. begin
  743.   while FDecisionDataLinks.Count > 0 do
  744.   begin
  745.     TDecisionDataLink(FDecisionDataLinks.Last).DecisionSource := nil;
  746.   end;
  747.   assert(FDecisionDataLinks.count = 0, 'Data Links did not free correctly');
  748.   FDecisionDataLinks.Free;
  749.   DecisionCube := nil;    { frees the cube link }
  750.   FData.Free;
  751.   FData := nil;
  752.   FSavePivotState.Free;
  753.   FSavePivotState := nil;
  754.   RowLookup.free;
  755.   RowLookup := nil;
  756.   ColLookup.free;
  757.   ColLookup := nil;
  758.   inherited Destroy;
  759. end;
  760.  
  761. function TDecisionSource.GetRowSparsing: Boolean;
  762. begin
  763.   Result := FData.FRowSparse;
  764. end;
  765.  
  766. procedure TDecisionSource.SetRowSparsing(Value: Boolean);
  767. begin
  768.   if FData.FRowSparse <> Value then
  769.   begin
  770.     if Ready then
  771.     begin
  772.       BeginChange;
  773.       FData.FRowSparse := Value;
  774.       EndChange(xePivot);
  775.       UpdateDesigner(self);
  776.     end;
  777.   end;
  778. end;
  779.  
  780. function TDecisionSource.GetColSparsing: Boolean;
  781. begin
  782.   Result := FData.FColSparse;
  783. end;
  784.  
  785. procedure TDecisionSource.SetColSparsing(Value: Boolean);
  786. begin
  787.   if FData.FColSparse <> Value then
  788.   begin
  789.     if Ready then
  790.     begin
  791.       BeginChange;
  792.       FData.FColSparse := Value;
  793.       EndChange(xePivot);
  794.       UpdateDesigner(self);
  795.     end;
  796.   end;
  797. end;
  798.  
  799. procedure TDecisionSource.DefineProperties(Filer: TFiler);
  800. begin
  801.   inherited;
  802.   Filer.DefineProperty('DimensionCount',ReadDimCount,WriteDimCount,True);
  803.   Filer.DefineProperty('SummaryCount',ReadSumCount,WriteSumCount,True);
  804.   Filer.DefineProperty('CurrentSummary',ReadCurrentSum,WriteCurrentSum,True);
  805.   Filer.DefineProperty('SparseRows',ReadRowSparse,WriteRowSparse,True);
  806.   Filer.DefineProperty('SparseCols',ReadColSparse,WriteColSparse,True);
  807.   Filer.DefineProperty('DimensionInfo',ReadDimInfo,WriteDimInfo,True);
  808. end;
  809.  
  810. procedure TDecisionSource.ReadDimCount(Reader: TReader);
  811. begin
  812.   FSavePivotState.FDims := Reader.ReadInteger;
  813. end;
  814.  
  815. procedure TDecisionSource.WriteDimCount(Writer: TWriter);
  816. begin
  817.   if Assigned(FData.DimInfo) then
  818.     Writer.WriteInteger(FData.DimInfo.limit)
  819.   else
  820.     Writer.WriteInteger(0);
  821. end;
  822.  
  823. procedure TDecisionSource.ReadSumCount(Reader: TReader);
  824. begin
  825.   FSavePivotState.FSums := Reader.ReadInteger;
  826. end;
  827.  
  828. procedure TDecisionSource.WriteSumCount(Writer: TWriter);
  829. begin
  830.   Writer.WriteInteger(Fdata.FSums);
  831. end;
  832. procedure TDecisionSource.ReadCurrentSum(Reader: TReader);
  833. begin
  834.   FSavePivotState.FCurrentSum := Reader.ReadInteger;
  835. end;
  836.  
  837. procedure TDecisionSource.WriteCurrentSum(Writer: TWriter);
  838. begin
  839.   Writer.WriteInteger(FData.FCurrentSum)
  840. end;
  841.  
  842. procedure TDecisionSource.ReadRowSparse(Reader: TReader);
  843. begin
  844.   FSavePivotState.FRowSparse := Reader.ReadBoolean;
  845. end;
  846.  
  847. procedure TDecisionSource.WriteRowSparse(Writer: TWriter);
  848. begin
  849.   Writer.WriteBoolean(FData.FRowSparse)
  850. end;
  851.  
  852. procedure TDecisionSource.ReadColSparse(Reader: TReader);
  853. begin
  854.   FSavePivotState.FColSparse := Reader.ReadBoolean;
  855. end;
  856.  
  857. procedure TDecisionSource.WriteColSparse(Writer: TWriter);
  858. begin
  859.   Writer.WriteBoolean(FData.FColSparse)
  860. end;
  861.  
  862. procedure TDecisionSource.ReadDimInfo(Reader: TReader);
  863. var
  864.   i,x: Integer;
  865.   aDimInfo: PDimInfo;
  866. begin
  867.   Reader.ReadListBegin;
  868.   FSavePivotState.DimInfo.Free;
  869.   FSavePivotState.DimInfo := TDimInfoArray.Create(FSavePivotState.FDims);
  870.   with FData do
  871.   begin
  872.     for i := 0 to FSavePivotState.DimInfo.Limit-1 do
  873.     begin
  874.       aDimInfo := FSavePivotState.DimInfo[i];
  875.       x := Reader.ReadInteger;
  876.       case x of
  877.         0: aDimInfo.iGroup := dgNone;
  878.         1: aDimInfo.iGroup := dgRow;
  879.         2: aDimInfo.iGroup := dgCol;
  880.         3: aDimINfo.iGroup := dgSum;
  881.       end;
  882.       aDimInfo.iActiveIndex := Reader.ReadInteger;
  883.       case Reader.ReadInteger of
  884.         0: aDimInfo.iState := dmNone;
  885.         1: aDimInfo.iState := dmOpen;
  886.         2: aDimInfo.iState := dmClosed;
  887.         3: aDimInfo.iState := dmDrilled;
  888.         4: aDimInfo.iState := dmPaged;
  889.       end;
  890.       aDimINfo.iIndex := Reader.ReadInteger;
  891.       aDimInfo.iValue := Reader.ReadInteger;
  892.     end;
  893.     Reader.ReadListEnd;
  894.     ProcessPivotState(FSavePivotState);
  895.     FSavePivotState.DimInfo.Free;
  896.     FSavePivotState.DimInfo := nil;
  897.     RebuildPivotState;
  898.     Buildlookups;
  899.     NotifyDataLinks(xeNewMetaData);
  900.   end;
  901. end;
  902.  
  903. procedure TDecisionSource.WriteDimInfo(Writer: TWriter);
  904. var
  905.   i: Integer;
  906.   aValue: Integer;
  907.   aDimInfo: PDimInfo;
  908. begin
  909.   Writer.WriteListBegin;
  910.   if Assigned(FData.DimInfo) then
  911.     with FData do
  912.     begin
  913.       for i := 0 to FData.DimInfo.limit-1 do
  914.       begin
  915.         aDimInfo := DimInfo[i];
  916.         if aDimInfo.iGroup = dgRow then
  917.           aValue := 1
  918.         else if aDimInfo.iGroup = dgCol then
  919.           aValue := 2
  920.         else if aDimInfo.iGroup = dgSum then
  921.           aValue := 3
  922.         else
  923.           aValue := 0;
  924.         Writer.WriteInteger(aValue);
  925.         Writer.WriteInteger(aDimInfo.iActiveIndex);
  926.         if aDimInfo.iState = dmOpen then
  927.           aValue := 1
  928.         else if aDimInfo.iState = dmClosed then
  929.           aValue := 2
  930.         else if aDimInfo.iState = dmDrilled then
  931.           aValue := 3
  932.         else if aDimInfo.iState = dmPaged then
  933.           aValue := 4
  934.         else
  935.           aValue := 0;
  936.         Writer.WriteInteger(aValue);
  937.         Writer.WriteInteger(aDimINfo.iIndex);
  938.         Writer.WriteInteger(aDimInfo.iValue);
  939.       end;
  940.     end;
  941.   Writer.WriteListEnd;
  942. end;
  943.  
  944. procedure TDecisionSource.BeginChange;
  945. begin
  946.   FChangeCount := FChangeCount + 1;
  947. end;
  948.  
  949. procedure TDecisionSource.EndChange(Event: TDecisionDataEvent);
  950. begin
  951.   RebuildPivotState;
  952.   if FChangeCount <= 1 then
  953.   begin
  954.     if assigned (FOnBeforePivot) then
  955.     begin
  956.       FOnBeforePivot(self);
  957.       RebuildPivotState;
  958.     end;
  959.     BuildLookups;
  960.     FChangeCount := 0;
  961.     NotifyDataLinks(Event);
  962.     if assigned (FOnAfterPivot) then FOnAfterPivot(self);
  963.   end
  964.   else
  965.     FChangeCount := FChangeCount-1;
  966. end;
  967.  
  968. procedure TDecisionSource.EnforceConstraints(dimGroup: TDimGroup; PreserveIndex: Integer);
  969. var
  970.   AllXDim: TIArray;
  971.   i: Integer;
  972.   bFound: Boolean;
  973. begin
  974.   Exit;
  975.   AllXDim := FData.DimInfo.GetGroupArray(dimGroup, False);
  976.   if (AllXDim.limit = 0) then Exit;
  977.   {
  978.     Check with xtRadio and xtRadioEx types to be sure that not more than one
  979.     dimension is on.  If PreserveIndex is set to a legal index, try to preserve
  980.     it's state active if it is already so.
  981.   }
  982.   if (FControlType in [xtRadio, xtRadioEx]) then    { at most one can be active }
  983.   begin
  984.     bFound := False;
  985.     if (PreserveIndex >= 0) and (PreserveIndex < AllXDim.limit) then
  986.     begin
  987.       if FData.DimInfo[AllXDim[PreserveIndex]].IState = dmOpen then bFound := True
  988.     end;
  989.     { if Preserve Index not set, let the first one found stay on }
  990.     for i := 0 to AllXDim.limit-1 do
  991.     begin
  992.       if FData.DimInfo[AllXDim[i]].IState = dmOpen then
  993.       begin
  994.         if bFound and (i <> PreserveIndex) then
  995.           FData.DimInfo[AllXDim[i]].IState := dmClosed;
  996.         bFound := True;
  997.       end;
  998.     end;
  999.     {
  1000.       if RadioEx, be sure one dimension is turned on.  If possible, preserve
  1001.       the state of Preserve Index, but not at the expense of the constraint
  1002.     }
  1003.     if (FControlType = xtRadioEx) and (not bFound) then
  1004.     begin
  1005.       if (PreserveIndex <> 0) or (AllXDim.limit = 1) then
  1006.         FData.DimInfo[AllXDim[0]].IState := dmOpen
  1007.       else
  1008.         FData.DimInfo[AllXDim[1]].IState := dmOpen;
  1009.     end;
  1010.   end;
  1011. end;
  1012.  
  1013. {
  1014.   SetUpData's function is to check to respond to large scale changes in the
  1015.   cube state (active/inactive changes, data availability, changes in
  1016.   meta data) and to restructure the dimension and row and column info
  1017.   as needed.
  1018.  
  1019.   SetUpData will not destroy state or pivot information unless
  1020.   there is new information to replace it.
  1021.  
  1022.   Setup the DecisionData Information, except that which requires pivot state
  1023.   FDims: Integer;
  1024.   FSums: Integer;
  1025.   RowSubs: Boolean;
  1026.   ColSubs: Boolean;
  1027.   RowSparse: Boolean;
  1028.   ColSparse: Boolean;
  1029.   DimInfo: TDimInfoArray;
  1030.  
  1031.   SetUpData will rebuild the Lookups as needed.
  1032. }
  1033.  
  1034. procedure TDecisionSource.SetUpData;
  1035. var
  1036.   I,J,OldI: Integer;
  1037.   DM: TCubeDim;
  1038.   aDimInfo: pDimInfo;
  1039.   OldArray: TDimInfoArray;
  1040.   bAccept: Boolean;
  1041. begin
  1042.   BeginChange;
  1043.   if Ready and (DecisionCube.DimensionCount>0) and (DecisionCube.SummaryCount>0) then
  1044.     with FData do
  1045.     begin
  1046.       bAccept := assigned(DimInfo) and (DimInfo.FDimNames.count = 0)
  1047.                                    and (DecisionCube.DimensionCount = FDims)
  1048.                                    and (DecisionCube.SummaryCount = FSums);
  1049.       if (FCurrentSum >= DecisionCube.SummaryCount) then
  1050.         FCurrentSum := 0;
  1051.       FDims := DecisionCube.DimensionCount;
  1052.       FSums := DecisionCube.SummaryCount;
  1053.       FActiveROws := 0;
  1054.       FActiveCols := 0;
  1055.       FAllRows := 0;
  1056.       FAllCols := 0;
  1057.       FAllPages := 0;
  1058.       { set up the diminfo and row and column arrays }
  1059.       oldArray := DimInfo;
  1060.       DimInfo := TDimInfoArray.Create(FDims);
  1061.       for I := 0 to DimInfo.Limit-1 do
  1062.       begin
  1063.     aDimInfo := DimInfo[i];
  1064.     aDimInfo.iValue := 0;
  1065.     DM := DecisionCube.DimensionMap[i];
  1066.     DimInfo.FDimNames.Add(DM.Fieldname);
  1067.     if bAccept then
  1068.     begin
  1069.       aDimInfo.iGroup := OldArray[i].iGroup;
  1070.       aDimInfo.iState := OldArray[i].iState;
  1071.       aDimInfo.iValue := OldArray[i].iValue;
  1072.           aDimInfo.IIndex := OldArray[i].IIndex;
  1073.           aDimInfo.IActiveIndex := OldArray[i].IActiveIndex;
  1074.     end
  1075.         else if (assigned(oldArray) and OldArray.Find(DM.Fieldname, oldi)) then
  1076.     begin
  1077.       aDimInfo.iGroup := OldArray[oldi].iGroup;
  1078.       aDimInfo.iState := OldArray[oldi].iState;
  1079.       aDimInfo.iValue := OldArray[oldi].iValue;
  1080.     end
  1081.     else if (DM.BinType = Binset) and (DM.StartValue <> '') then
  1082.         begin
  1083.       aDimInfo.iState := dmPaged;
  1084.         end
  1085.     else
  1086.         begin
  1087.           if FActiveCols = 0 then
  1088.           begin
  1089.             aDimInfo.iGroup := dgCol;
  1090.         aDimInfo.IState := dmOpen;
  1091.         aDimInfo.iValue := -1;
  1092.           end
  1093.       else
  1094.           begin
  1095.             aDimInfo.iGroup := dgRow;
  1096.             aDimInfo.iValue := -1;
  1097.         if FActiveRows = 0 then
  1098.           aDimInfo.IState := dmOpen
  1099.           else
  1100.               aDimInfo.Istate := dmClosed;
  1101.           end;
  1102.         end;
  1103.     if (DM.BinType = Binset) and (DM.StartValue <> '') then
  1104.         begin
  1105.       aDimInfo.iState := dmPaged;
  1106.       aDimInfo.IGroup := dgPage;
  1107.       aDimInfo.iValue := 0;
  1108.       for J := 0 to GetDimensionMemberCount(i)-1 do
  1109.           begin
  1110.         if GetMemberAsString(i,j) <> DM.BinData.OtherBinName then
  1111.             begin
  1112.           aDimInfo.iValue := j;
  1113.               break;
  1114.         end;
  1115.           end;
  1116.         end
  1117.         else if (aDimInfo.iGroup = dgPage) then
  1118.         begin
  1119.           aDimInfo.IGroup := dgRow;
  1120.           aDimInfo.iState := dmOpen;
  1121.         end;
  1122.         { now set the active indexex }
  1123.         if not bAccept then
  1124.         begin
  1125.           if (aDimInfo.iGroup = dgRow) then
  1126.           begin
  1127.         aDimInfo.iIndex := FAllRows;
  1128.         FAllRows := FAllRows + 1;
  1129.             if aDimInfo.iState = dmOpen then
  1130.             begin
  1131.               aDimInfo.iActiveIndex := FActiveRows;
  1132.           FActiveRows := FActiveRows + 1;
  1133.             end
  1134.             else
  1135.               aDimInfo.iActiveIndex := -1;
  1136.           end
  1137.           else if aDimInfo.iGroup = dgCol then
  1138.           begin
  1139.         aDimInfo.iIndex := FAllCols;
  1140.             FAllCols := FAllCols + 1;
  1141.             if aDimInfo.iState = dmOpen then
  1142.             begin
  1143.               aDimInfo.iActiveIndex := FActiveCols;
  1144.           FActiveCols := FActiveCols + 1;
  1145.             end
  1146.             else
  1147.               aDimInfo.iActiveIndex := -1;
  1148.             end
  1149.             else
  1150.             begin
  1151.           aDimInfo.iIndex := FAllPages;
  1152.               aDimInfo.iActiveIndex := FAllPages;
  1153.           FAllPages := FAllPages + 1;
  1154.             end;
  1155.           end;
  1156.         end;
  1157.     OldArray.free;
  1158.         EnforceConstraints(dgRow, -1);
  1159.         EnforceConstraints(dgCol, -1);
  1160.         {
  1161.           finally, the rest of the Decision data structure.  Note the GetExampleRepCount
  1162.           depends on the rest being set up
  1163.         }
  1164.         FRowSubs := True;
  1165.         FColSubs := True;
  1166.       end;
  1167.   EndChange(xeNewMetaData);
  1168. end;
  1169.  
  1170. {
  1171.   Reset the DimInfo information IIndex and IRowState
  1172.  
  1173.   Coming here, RowAllDim and ColAllDim contain the information about
  1174.   row and column placement, and DimInfo is correct for everything else.
  1175.   This routine brings these two into correspondence, and also resets
  1176.   FAllRows, FAllCols, FActiveRows, FActiveCols
  1177. }
  1178.  
  1179. procedure TDecisionSource.RebuildPivotState;
  1180. var
  1181.   I, IDim, IActive: Integer;
  1182.   aInfo: PDimInfo;
  1183.   pState,aState: TDimState;
  1184.   AllXDim: TIArray;
  1185. begin
  1186.   {
  1187.     rebuild the lookup tables from the Row and Col Dimension Info
  1188.     This needs to be done at every pivot or drill
  1189.   }
  1190.   if (not Ready) or (FData.FDims = 0) or (FData.FSums = 0) then
  1191.     with FData do
  1192.     begin
  1193.       FActiveRows := 0;
  1194.       FActiveCols := 0;
  1195.       FAllRows := 0;
  1196.       FAllCols := 0;
  1197.     end
  1198.   else
  1199.     with FData do
  1200.     begin
  1201.       pState := dmNone;
  1202.       AllXDim := DimInfo.GetGroupArray(dgRow, False);
  1203.       for I := AllXDim.Limit-1 downto 0 do
  1204.       begin
  1205.         IDim := AllXDim[i];
  1206.     aInfo := DimInfo[IDim];
  1207.     if pState = dmOpen then
  1208.           aInfo.iRowState := [rcNextOpen]
  1209.     else if (pState = dmClosed) then
  1210.           aInfo.iRowState := [rcNextClosed]
  1211.         else aInfo.iRowState := [];
  1212.     aState := aInfo.Istate;
  1213.         if (aState = dmClosed) then pState := dmClosed;
  1214.         if (aState = dmOpen) then pState := dmOpen;
  1215.       end;
  1216.       IActive := 0;
  1217.       pState := dmNone;
  1218.       for I := 0 to AllXDim.Limit-1 do
  1219.       begin
  1220.         IDim := AllXDim[i];
  1221.     aInfo := DimInfo[IDim];
  1222.     if (pState = dmOpen) then
  1223.           aInfo.iRowState := aInfo.iRowState + [rcPrevOpen]
  1224.     else if (pState = dmClosed) then
  1225.           aInfo.iRowState := aInfo.iRowState + [rcPrevClosed];
  1226.     aState := aInfo.Istate;
  1227.         aInfo.IActiveIndex := -1;
  1228.     if (aState = dmOpen) then
  1229.         begin
  1230.       aInfo.iRowState := aInfo.iRowState + [rcPrevOpen];
  1231.       aInfo.iActiveIndex := IActive;
  1232.       IActive := IActive + 1;
  1233.       end;
  1234.         if (aState = dmClosed) then pState := dmClosed;
  1235.        if (aState = dmOpen) then pState := dmOpen;
  1236.       end;
  1237.       FActiveRows := IActive;
  1238.       FAllRows := AllXDim.limit;
  1239.       AllXDim := DimInfo.GetGroupArray(dgCol, False);
  1240.       pState := dmNone;
  1241.       for I := AllXDim.Limit-1 downto 0 do
  1242.       begin
  1243.         IDim := AllXDim[i];
  1244.     aInfo := DimInfo[IDim];
  1245.         if (pState = dmOpen) then
  1246.           aInfo.iRowState := [rcNextOpen]
  1247.         else if (pState = dmClosed) then
  1248.           aInfo.iRowState := [rcNextClosed]
  1249.     else aInfo.iRowState := [];
  1250.     aState := aInfo.Istate;
  1251.         if (aState = dmClosed) then pState := dmClosed;
  1252.         if (aState = dmOpen) then pState := dmOpen;
  1253.       end;
  1254.       IActive := 0;
  1255.       pState := dmNone;
  1256.       for I := 0 to AllXDim.Limit-1 do
  1257.       begin
  1258.         IDim := AllXDim[i];
  1259.     aInfo := DimInfo[IDim];
  1260.     if (pState = dmOpen) then
  1261.           aInfo.iRowState := aInfo.iRowState + [rcPrevOpen]
  1262.     else if (pState = dmClosed) then
  1263.           aInfo.iRowState := aInfo.iRowState + [rcPrevClosed];
  1264.         aState := aInfo.Istate;
  1265.         aInfo.IActiveIndex := -1;
  1266.         if (aState = dmOpen) then
  1267.         begin
  1268.       aInfo.iActiveIndex := IActive;
  1269.       IActive := IActive + 1;
  1270.       end;
  1271.         if (aState = dmClosed) then pState := dmClosed;
  1272.         if (aState = dmOpen) then pState := dmOpen;
  1273.       end;
  1274.       FActiveCols := IActive;
  1275.       FAllCols := AllXDIm.limit;
  1276.       { Now initialize the summaries to reflect the correct FActiveSum }
  1277.       if FCurrentSum >= FSums then FCurrentSum := 0;
  1278.     end;
  1279. end;
  1280.  
  1281. procedure TDecisionSource.BuildLookups;
  1282. var
  1283.   iDim: Integer;
  1284.   I: Integer;
  1285.   RowDim, ColDim: TIntArray;
  1286. begin
  1287.   {
  1288.     rebuild the lookup tables from the Row and Col Dimension Info
  1289.     This needs to be done at every pivot or drill
  1290.   }
  1291.   if (not Ready) or (FData.FDims = 0) or (FData.FSums = 0) then
  1292.   begin
  1293.     FRowMax := 1;
  1294.     FColMax := 1;
  1295.     RowLookup.free;
  1296.     ColLookup.Free;
  1297.     RowLookup := nil;
  1298.     ColLookup := nil;
  1299.   end
  1300.   else
  1301.     with FData do
  1302.     begin
  1303.       { Now initialize the summaries to reflect the correct FActiveSum }
  1304.       if (FCurrentSum >= FSums) then
  1305.         FCurrentSum := 0;
  1306.       DecisionCube.SetCurrentSummary(FCurrentSum);
  1307.       if Ready and ((FState = dcBrowseAllData)  or (FState = dcBrowseMemberData)) then
  1308.       begin
  1309.         RowDim := TIntArray.Create(0,0);
  1310.     ColDim := TIntArray.Create(0,0);
  1311.     try
  1312.       iDim := 0;
  1313.       for i := 0 to FActiveRows-1 do
  1314.             RowDim.InsertAt(0,iDim);
  1315.           for i := 0 to FActiveCols-1 do
  1316.             ColDim.InsertAt(0,iDim);
  1317.       for i := 0 to DimInfo.limit-1 do
  1318.           begin
  1319.         if (DimInfo[i].iState = dmOpen) then
  1320.             begin
  1321.           if (DimInfo[i].iGroup = dgRow) then
  1322.               begin
  1323.             assert(DimInfo[i].iActiveIndex < FActiveRows, 'Error is active rows');
  1324.                 if (DimInfo[i].iActiveIndex >= FActiveRows) then
  1325.                   raise exception.createRes(@sRowError);
  1326.                 RowDim[DimInfo[i].iActiveIndex] := i;
  1327.           end;
  1328.           if (DimInfo[i].iGroup = dgCol) then
  1329.               begin
  1330.             assert(DimInfo[i].iActiveIndex < FActiveCols, 'Error is active cols');
  1331.                 if (DimInfo[i].iActiveIndex >= FActiveCols) then
  1332.                   raise exception.createRes(@sRowError);
  1333.                 ColDim[DimInfo[i].iActiveIndex] := i;
  1334.               end;
  1335.             end;
  1336.           end;
  1337.       RowLookup.free;
  1338.       RowLookup := nil;
  1339.           ColLookUp.free;
  1340.             ColLookUp := nil;
  1341.              RowLookup := TTwoDimArray.Create;
  1342.           ColLookup := TTwoDimArray.Create;
  1343.           if (FState <> dcBrowseAllData) then
  1344.             FDecisionCube.Sparsing := False
  1345.       else
  1346.             FDecisionCube.Sparsing := not FRowSparse;
  1347.           FRowMax := FDecisionCube.GetDomain(RowDim,FRowSubs,RowLookup);
  1348.       if (FState <> dcBrowseAllData) then
  1349.             FDecisionCube.Sparsing := False
  1350.       else
  1351.             FDecisionCube.Sparsing := not FColSparse;
  1352.       FColMax := FDecisionCube.GetDomain(ColDim,FColSubs,ColLookup);
  1353.     finally
  1354.       RowDim.free;
  1355.       ColDim.free;
  1356.     end;
  1357.       end
  1358.       else if Ready and (FState = dcBrowseMetaData) then
  1359.       begin
  1360.         FRowMax := 1;
  1361.         if (FActiveCols = 0) then
  1362.           FColMax := 1
  1363.         else
  1364.           FColMax := FActiveCols;
  1365.     RowLookup.free;
  1366.     ColLookup.Free;
  1367.     RowLookup := nil;
  1368.         ColLookup := nil;
  1369.       end
  1370.       else
  1371.       begin
  1372.     FRowMax := 1;
  1373.         FColMax := 1;
  1374.     RowLookup.free;
  1375.     ColLookup.Free;
  1376.     RowLookup := nil;
  1377.         ColLookup := nil;
  1378.       end;
  1379.     end;
  1380. end;
  1381.  
  1382. procedure TDecisionSource.FetchPivotState(var FState: TPivotState);
  1383. begin
  1384.   FState.Assign(FData);
  1385. end;
  1386.  
  1387. procedure TDecisionSource.StorePivotState(FState: TPivotState);
  1388. begin
  1389.   BeginChange;
  1390.   ProcessPivotState(FState);
  1391.   EndChange(xeNewMetaData);
  1392. end;
  1393.  
  1394. procedure TDecisionSource.ProcessPivotState(FState: TPivotState);
  1395. var
  1396.   i: Integer;
  1397.   aDimInfo: PDimInfo;
  1398. begin
  1399.   with FData do
  1400.   begin
  1401.     FDims := FState.FDims;
  1402.     if not assigned(DimInfo) then
  1403.       DimInfo := TDimInfoArray.create(FDims);
  1404.     DimInfo.Assign(FState.DimInfo);
  1405.     FCurrentSum := FState.FCurrentSum;
  1406.     FSums := FState.FSums;
  1407.     FRowSparse := FState.FRowSparse;
  1408.     FColSparse := FState.FColSparse;
  1409.     FRowSubs := True;
  1410.     FColSubs := True;
  1411.     FAllRows := 0;
  1412.     FAllCols:= 0;
  1413.     FActiveRows:= 0;
  1414.     FActiveCols:= 0;
  1415.     for i := 0 to DimInfo.limit -1 do
  1416.     begin
  1417.       aDimInfo := DimInfo[i];
  1418.       if aDimInfo.iGroup = dgRow then
  1419.       begin
  1420.         FAllRows:= FAllRows + 1;
  1421.         if (aDimInfo.IState = dmOpen) then
  1422.           FActiveRows := FActiveRows + 1;
  1423.       end;
  1424.       if (aDimInfo.iGroup = dgCol) then
  1425.       begin
  1426.         FAllCols := FAllCols + 1;
  1427.         if (aDimInfo.IState = dmOpen) then
  1428.           FActiveCols := FActiveCols + 1;
  1429.       end;
  1430.     end;
  1431.     FDims := FAllRows + FAllCols;
  1432.     SetupData;
  1433.   end;
  1434. end;
  1435.  
  1436. procedure TDecisionSource.AddDataLink(Link: TDecisionDataLink);
  1437. begin
  1438.   FDecisionDataLinks.Add(Link);
  1439.   Link.FDecisionSource := Self;
  1440. end;
  1441.  
  1442. procedure TDecisionSource.RemoveDataLink(Link: TDecisionDataLink);
  1443. begin
  1444.   link.FDecisionSource := nil;
  1445.   FDecisionDataLinks.Remove(Link);
  1446. end;
  1447.  
  1448. procedure TDecisionSource.NotifyDataLinks(Event: TDecisionDataEvent);
  1449. var
  1450.   I: Integer;
  1451. begin
  1452.   if (FChangeCount > 0) then Exit;
  1453.   for I := FDecisionDataLinks.Count - 1 downto 0 do
  1454.     with TDecisionDataLink(FDecisionDataLinks[I]) do
  1455.     begin
  1456.       DecisionDataEvent(Event);
  1457.     end;
  1458.     if (csDesigning in ComponentState) and not (csLoading in ComponentState) then
  1459.     begin
  1460.       if Event in [xePivot, xeSummaryChanged] then
  1461.       begin
  1462.         UpdateDesigner(self);
  1463.       end;
  1464.     end;
  1465.     case Event of
  1466.       xePivot:
  1467.       begin
  1468.         if assigned(FOnLayoutChange) then
  1469.           FOnLayoutChange(self);
  1470.       end;
  1471.       xeNewMetaData:
  1472.       begin
  1473.         if assigned(FOnNewDimensions) then
  1474.           FOnNewDimensions(self);
  1475.       end;
  1476.       xeStateChanged:
  1477.       begin
  1478.         if assigned (FOnStateChange) then
  1479.           FOnStateChange(self);
  1480.       end;
  1481.       xeSummaryChanged:
  1482.       begin
  1483.         if assigned(FOnSummaryChange) then
  1484.           FOnSummaryChange(self);
  1485.       end;
  1486.     end;
  1487. end;
  1488.  
  1489. {
  1490.   Pivoting functions
  1491.  
  1492.   open the first inactive row/col to the immediate right of the Active row/col = Index
  1493.   if Index = -1, it means open the first row
  1494. }
  1495.  
  1496. procedure TDecisionSource.OpenDimIndexRight(dimGroup: TDimGroup; Index: Integer; bOpen: Boolean);
  1497. var
  1498.   i,j: Integer;
  1499.   aDimInfo: PDimInfo;
  1500.   AllXDim: TIArray;
  1501. begin
  1502.   with FData do
  1503.   begin
  1504.     if (Index < 0) then
  1505.       i := -1
  1506.     else
  1507.       i := DimInfo.GetGroupItem(dimGroup,Index,bOpen).iIndex;
  1508.     AllXDim := DimInfo.GetGroupArray(dimGroup, False);
  1509.     if (i < AllXDim.Limit-1) then
  1510.     begin
  1511.       for j := i+1 to AllXDim.limit-1 do
  1512.       begin
  1513.         aDimInfo := DimInfo[AllXDim[j]];
  1514.     if (aDimInfo.IState = dmClosed) then
  1515.         begin
  1516.       BeginChange;
  1517.       aDimInfo.IState := dmOpen;
  1518.       aDimInfo.IValue := 0;
  1519.           EnforceConstraints(dimGroup, j);
  1520.           EndChange(xePivot);
  1521.             Exit;
  1522.     end;
  1523.       end;
  1524.     end;
  1525.   end;
  1526. end;
  1527.  
  1528. {
  1529.   close all active rows/cols to the immediate right of the Active row/col = Index
  1530.   if Index = -1, it means start with the first row/col
  1531. }
  1532.  
  1533. procedure TDecisionSource.CloseDimIndexRight(dimGroup: TDimGroup; Index: Integer; bOpen: Boolean);
  1534. var
  1535.   i,j,count: Integer;
  1536.   aDimInfo: PDimInfo;
  1537.   AllXDim: TIArray;
  1538. begin
  1539.   with FData do
  1540.   begin
  1541.     if (Index = -1) then
  1542.       i := -1
  1543.     else
  1544.       i := DimInfo.GetGroupItem(dimGroup,Index,bOpen).iIndex;
  1545.     count := 0;
  1546.     AllxDim := DimInfo.GetGroupArray(dimGroup, True);
  1547.     if (i < AllxDim.Limit-1) then
  1548.     begin
  1549.       for j := i+1 to AllxDim.limit-1 do
  1550.       begin
  1551.         aDimInfo := DimInfo[AllxDim[j]];
  1552.         if (aDimInfo.IState = dmOpen) then
  1553.         begin
  1554.           if (count = 0) then
  1555.             BeginChange;
  1556.           aDimInfo.IState := dmClosed;
  1557.           aDimInfo.IValue := 0;
  1558.           count := count + 1;
  1559.         end;
  1560.       end;
  1561.       if (count > 0) then
  1562.       begin
  1563.         EnforceConstraints(dimGroup, -1);
  1564.         EndChange(xePivot);
  1565.       end;
  1566.     end;
  1567.   end;
  1568. end;
  1569.  
  1570. procedure TDecisionSource.OpenDimIndexLeft(dimGroup: TDimGroup; Index: Integer; bOpen: Boolean);
  1571. var
  1572.   i,j: Integer;
  1573.   aDimInfo: PDimInfo;
  1574.   Allxdim: TIArray;
  1575. begin
  1576.   with FData do
  1577.   begin
  1578.     i := DimInfo.GetGroupItem(dimGroup,Index,bOpen).iIndex;
  1579.     if (i < 1) then Exit;
  1580.     AllxDim := DimInfo.GetGroupArray(dimGroup, False);
  1581.     if (dimGroup = dgRow) then
  1582.     begin
  1583.       for j := i-1 downto 0 do
  1584.       begin
  1585.         aDimInfo := DimInfo[AllxDim[j]];
  1586.         if aDimInfo.IState = dmClosed then
  1587.         begin
  1588.           BeginChange;
  1589.           aDimInfo.IState := dmOpen;
  1590.           aDimInfo.IValue := 0;
  1591.           EnforceConstraints(dimGroup, j);
  1592.           EndChange(xePivot);
  1593.         end;
  1594.       end;
  1595.     end;
  1596.   end;
  1597. end;
  1598.  
  1599. procedure TDecisionSource.ToggleDimIndex(dimGroup: TDimGroup; Index: Integer; bOpen: Boolean);
  1600. var
  1601.   aDimInfo: PDimInfo;
  1602.   iDim: Integer;
  1603. begin
  1604.   with FData do
  1605.   begin
  1606.     iDim := GetActiveDim(dimGroup, Index, bOpen);
  1607.     if (iDim >= 0) then
  1608.     begin
  1609.       aDimInfo := Diminfo[iDim];
  1610.       if aDimInfo.IState = dmPaged then Exit;
  1611.       BeginChange;
  1612.       if (aDimInfo.IState = dmOpen) then
  1613.         aDimInfo.IState := dmClosed
  1614.       else
  1615.       begin
  1616.         aDimInfo.IState := dmOpen;
  1617.     aDimInfo.IValue := 0;
  1618.       end;
  1619.       EnforceConstraints(aDimInfo.IGroup, aDimInfo.IIndex);
  1620.       EndChange(xePivot);
  1621.     end;
  1622.   end;
  1623. end;
  1624.  
  1625. { Data Access Functions }
  1626.  
  1627. function  TDecisionSource.GetReady: Boolean;
  1628. begin
  1629.   Result := bActivated;
  1630. end;
  1631.  
  1632. function  TDecisionSource.GetDataAsString(ARow, ACol: Integer; var SubLevel: Integer): String;
  1633. var
  1634.   I, iLook: Integer;
  1635.   DI: pDimInfo;
  1636.   Coord: TSmallIntArray;
  1637. begin
  1638.   if Ready and (FState = dcBrowseAllData) then
  1639.     with FData do
  1640.     begin
  1641.       Coord := TSmallIntArray.Create(FDims, 0);
  1642.       try
  1643.         SubLevel := 0;
  1644.         for i := 0 to FData.DimInfo.limit-1 do
  1645.         begin
  1646.           DI := DimInfo[i];
  1647.           if (DI.IState = dmOpen) and (DI.iGroup = dgRow) then
  1648.           begin
  1649.             iLook := RowLookup[DI.iActiveIndex, aRow];
  1650.             if (iLook = Subtotal) then SubLevel := SubLevel + 1;
  1651.           end
  1652.           else if (DI.IState = dmOpen) and (DI.iGroup = dgCol) then
  1653.           begin
  1654.             iLook := ColLookup[DI.iActiveIndex, aCol];
  1655.             if (iLook = Subtotal) then SubLevel := SubLevel + 1;
  1656.           end
  1657.           else if (DimInfo[I].IState in [dmDrilled, dmPaged]) then
  1658.             iLook := DimInfo[I].IValue
  1659.           else
  1660.             iLook := subtotal;
  1661.           Coord[i] := iLook;
  1662.         end;
  1663.         Result := FDecisionCube.GetSummaryAsString(Coord);
  1664.       finally
  1665.         Coord.free;
  1666.       end;
  1667.   end
  1668.   else
  1669.     Result := '';
  1670. end;
  1671.  
  1672. function TDecisionSource.GetMemberAsString(iDim: Integer; ValueIndex: Integer): String;
  1673. begin
  1674.   if Ready and ((FState = dcBrowseAllData) or (FState = dcBrowseMemberData)) then
  1675.     Result := FDecisionCube.GetMemberAsString(iDim, ValueIndex)
  1676.   else
  1677.     Result := '';
  1678. end;
  1679.  
  1680. function TDecisionSource.GetMemberAsVariant(iDim: Integer; ValueIndex: Integer): Variant;
  1681. begin
  1682.   if Ready and ((FState = dcBrowseAllData) or (FState = dcBrowseMemberData)) then
  1683.     Result := FDecisionCube.GetMemberAsVariant(iDim, ValueIndex)
  1684.   else
  1685.     Result := '';
  1686. end;
  1687.  
  1688. function TDecisionSOurce.GetSummaryName(iSum: Integer): String;
  1689. begin
  1690.   if Ready then
  1691.     Result := FDecisionCube.GetSummaryName(iSum)
  1692.   else
  1693.     Result := '';
  1694. end;
  1695.  
  1696. procedure TDecisionSource.SetCurrentSummary(Value: Integer);
  1697. begin
  1698.   if assigned(DecisionCube) and (Value < DecisionCube.SummaryCount) and (Value >= 0) then
  1699.   begin
  1700.     DecisionCube.SetCurrentSummary(Value);
  1701.   end;
  1702.   FData.FCurrentSum := Value;
  1703.   NotifyDataLinks(xeSummaryChanged);
  1704. end;
  1705.  
  1706. function  TDecisionSource.GetDimensionName(iDim: Integer): String;
  1707. begin
  1708.   Result := '';
  1709.   if Ready then
  1710.     Result := FDecisionCube.GetDimensionName(iDim);
  1711. end;
  1712.  
  1713. function TDecisionSource.GetDimensionMemberCount(iDim: Integer): Integer;
  1714. begin
  1715.   if Ready and ((FState = dcBrowseAllData) or (FState = dcBrowseMemberData)) then
  1716.     Result := FDecisionCube.GetDimensionMemberCount(iDim)
  1717.   else
  1718.     Result := 0;
  1719. end;
  1720.  
  1721. function  TDecisionSource.GetDataAsVariant(ARow, ACol: Integer; var SubLevel: Integer): Variant;
  1722. var
  1723.   I, iLook: Integer;
  1724.   DI: pDimInfo;
  1725.   Coord: TSmallIntArray;
  1726. begin
  1727.   if Ready and (FState = dcBrowseAllData) then
  1728.     with FData do
  1729.     begin
  1730.       Coord := TSmallIntArray.Create(FDims, 0);
  1731.       try
  1732.         SubLevel := 0;
  1733.     for i := 0 to FData.DimInfo.limit-1 do
  1734.           begin
  1735.       DI := DimInfo[i];
  1736.       if (DI.IState = dmOpen) and (DI.iGroup = dgRow) then
  1737.           begin
  1738.             iLook := RowLookup[DI.iActiveIndex, aRow];
  1739.         if (iLook = Subtotal) then SubLevel := SubLevel + 1;
  1740.           end
  1741.           else if (DI.IState = dmOpen) and (DI.iGroup = dgCol) then
  1742.           begin
  1743.             iLook := ColLookup[DI.iActiveIndex, aCol];
  1744.         if (iLook = Subtotal) then SubLevel := SubLevel + 1;
  1745.       end
  1746.       else if (DimInfo[I].IState in [dmDrilled, dmPaged]) then
  1747.             iLook := DimInfo[I].IValue
  1748.           else
  1749.             iLook := subtotal;
  1750.       Coord[i] := iLook;
  1751.     end;
  1752.     Result := FDecisionCube.GetSummaryAsVariant(Coord);
  1753.       finally
  1754.     Coord.free;
  1755.       end;
  1756.     end
  1757.   else
  1758.     Result := '';
  1759. end;
  1760.  
  1761. function TDecisionSource.Get2DDataAsVariant(iDimA, iDimB: Integer;
  1762.          aValueIndex, bValueIndex: Integer): Variant;
  1763. var
  1764.   I: Integer;
  1765.   Coord: TSmallIntArray;
  1766. begin
  1767.   if Ready and (FState = dcBrowseAllData) then
  1768.     with FData do
  1769.     begin
  1770.       Coord := TSmallIntArray.Create(FDims, 0);
  1771.       try
  1772.         for I := 0 to Coord.Limit-1 do
  1773.         begin
  1774.           if (DimInfo[I].IState in [dmDrilled, dmPaged]) then
  1775.             Coord[I] := DimInfo[I].IValue
  1776.           else if (I = iDimA) then
  1777.             Coord[i] := aValueIndex
  1778.           else if (I = iDimB) then
  1779.             Coord[i] := bValueIndex
  1780.           else
  1781.             Coord[I] := Subtotal;
  1782.         end;
  1783.     Result := FDecisionCube.GetSummaryAsVariant(Coord);
  1784.       finally
  1785.     Coord.free;
  1786.       end;
  1787.     end
  1788.   else
  1789.     Result := 0;
  1790. end;
  1791.  
  1792. function TDecisionSource.GetValueIndex(dimGroup: TDimGroup; Index: Integer; Cell:
  1793.          Integer; var isBreak: Boolean; var isSum: Boolean) : Integer;
  1794. var
  1795.   I,J,Temp: Integer;
  1796.   subs: Boolean;
  1797.   LastVal: Integer;
  1798. begin
  1799.   with FData do
  1800.     if (dimGroup = dgRow) then
  1801.       subs := FrowSubs
  1802.     else
  1803.       subs := FcolSubs;
  1804.   if Ready and (FState = dcBrowseAllData) or (FState = dcBrowseMemberData) then
  1805.   begin
  1806.     if (dimGroup = dgRow) then
  1807.       Result := RowLookup[Index,Cell]
  1808.     else
  1809.       Result := ColLookup[Index,Cell];
  1810.     if (Result < 0) then
  1811.       isSum := True
  1812.     else
  1813.       isSum := False;
  1814.     if (Cell = 0) then
  1815.       isBreak := True
  1816.     else
  1817.     begin
  1818.       if (dimGroup = dgRow) then
  1819.         LastVal := RowLookup[Index,Cell-1]
  1820.       else
  1821.         LastVal := ColLookup[Index,Cell-1];
  1822.       isBreak := Result <> LastVal;
  1823.     end;
  1824.   end
  1825.   else
  1826.   begin
  1827.     Temp := Cell;
  1828.     for I := 0 to Index do
  1829.     begin
  1830.       j := GetExampleRepCount(dimGroup, I);
  1831.       Temp := Temp mod j;
  1832.       if (Temp = j-1) then
  1833.         if subs then
  1834.     begin
  1835.       isSum := True;
  1836.           if (I = Index) then
  1837.             isBreak := True
  1838.           else
  1839.             isBreak := False;
  1840.       Result := Subtotal;
  1841.           Exit;
  1842.         end;
  1843.     end;
  1844.     j := GetExampleRepCount(dimGroup, Index+1);
  1845.     if ((Temp mod j) = 0) then
  1846.       isBreak := True
  1847.     else
  1848.       isBreak := False;
  1849.     Temp := Temp div j;
  1850.     Result := Temp;
  1851.     isSum := False;
  1852.   end;
  1853. end;
  1854.  
  1855. {
  1856.   Find the extent of the Group (including the sum) which is within Row or Column
  1857.   Dimension Index and at the Position Cell.
  1858. }
  1859.  
  1860. function TDecisionSource.GetGroupExtent(dimGroup: TDimGroup; Index: Integer; Cell: Integer): TDimRange;
  1861. var
  1862.   isBreak, isSum: Boolean;
  1863.   iMax: Integer;
  1864. begin
  1865.   Result.Last := Cell;
  1866.   Result.First := Cell;
  1867.   isBreak := False;
  1868.   {  Scan backward for the first group break which is not a sum }
  1869.   while (Result.First > 0) and (not isBreak) do
  1870.   begin
  1871.     GetValueIndex(dimGroup,Index,Result.First,isBreak,isSum);
  1872.     if (not isBreak) then
  1873.       Result.First := Result.First - 1;
  1874.   end;
  1875.   { Scan forward for the first break, then back off }
  1876.   if (dimGroup = dgRow) then
  1877.     iMax := FRowMax
  1878.   else
  1879.     iMax := FColMax;
  1880.   isBreak := False;
  1881.   while (Result.Last < iMax-1) and (not isBreak) do
  1882.   begin
  1883.     GetValueIndex(dimGroup,Index,Result.Last+1,isBreak,isSum);
  1884.     if (not isBreak) then
  1885.       Result.Last := Result.Last + 1;
  1886.   end;
  1887. end;
  1888.  
  1889. {
  1890.   These are the functions which are calls to the data cube through the source.
  1891.   They are not allowed if the source is not active.
  1892. }
  1893.  
  1894. function TDecisionSource.GetValueArray(ACol, ARow: Integer; var ValueArray: TSmallIntArray): Boolean;
  1895. var
  1896.   i: Integer;
  1897. begin
  1898.   with FData do
  1899.   begin
  1900.     ValueArray.clear;
  1901.     for i := 0 to FDims-1 do
  1902.     begin
  1903.       if (DimInfo[i].iState in [dmDrilled, dmPaged]) then
  1904.         ValueArray.Add(DimInfo[i].iValue)
  1905.       else if (DimInfo[i].iState = dmClosed) then
  1906.         ValueArray.add(subtotal)
  1907.       else if (DimInfo[i].iGroup = dgRow) then
  1908.       begin
  1909.         if (ARow < 0) then
  1910.           ValueArray.add(subtotal)
  1911.         else
  1912.           ValueArray.add(RowLookup[DimInfo[i].iActiveIndex, ARow]);
  1913.       end
  1914.       else
  1915.       begin
  1916.         if (ACol < 0) then
  1917.           ValueArray.add(subtotal)
  1918.         else
  1919.           ValueArray.add(ColLookup[DimInfo[i].iActiveIndex, ACol]);
  1920.       end;
  1921.     end;
  1922.     Result := True;
  1923.   end;
  1924. end;
  1925.  
  1926. function TDecisionSource.GetDecisionCube: TDecisionCube;
  1927. begin
  1928.   Result := FDecisionCube;
  1929. end;
  1930.  
  1931. procedure TDecisionSource.SetDecisionCube(Value: TDecisionCube);
  1932. begin
  1933.   if (FDecisionCube <> Value) then
  1934.   begin
  1935.     if (FDecisionCube <> nil) then
  1936.       FDecisionCube.RemoveDataSource(Self);
  1937.     if (Value <> nil) then
  1938.     begin
  1939.       Value.AddDataSource(Self);
  1940.     end;
  1941.     FDecisionCube := Value;
  1942.     DecisionDataEvent(xeStateChanged);
  1943.   end;
  1944. end;
  1945.  
  1946. procedure TDecisionSource.DecisionDataEvent(Event: TDecisionDataEvent);
  1947. begin
  1948.   if FBlocked then Exit;
  1949.   FBlocked := True;
  1950.   if (Event = xeStateChanged) then
  1951.   begin
  1952.     if not assigned(DecisionCube) then
  1953.     begin
  1954.       bActivated := False;
  1955.     end
  1956.     else
  1957.     begin
  1958.       FState := DecisionCube.State;
  1959.       if (FState = dcInactive) then
  1960.         bActivated := False
  1961.       else
  1962.         bActivated := True;
  1963.       SetUpData;
  1964.     end;
  1965.   end;
  1966.   NotifyDataLinks(Event);
  1967.   FBlocked := False;
  1968. end;
  1969.  
  1970. { TDecisionDataLink }
  1971.  
  1972. constructor TDecisionDataLink.Create;
  1973. begin
  1974.   FBlocked := False;
  1975. end;
  1976.  
  1977. destructor TDecisionDataLink.Destroy;
  1978. begin
  1979.   SetDecisionSource(nil);
  1980.   inherited Destroy;
  1981. end;
  1982.  
  1983. procedure TDecisionDataLink.DecisionDataEvent(Event: TDecisionDataEvent);
  1984. begin
  1985. end;
  1986.  
  1987. procedure TDecisionDataLink.SetDecisionSource(source: TDecisionSource);
  1988. begin
  1989.   if (FDecisionSource <> Source) then
  1990.   begin
  1991.     if (FDecisionSource <> nil) then
  1992.       FDecisionSource.RemoveDataLink(Self);
  1993.     if (Source <> nil) then Source.AddDataLink(Self);
  1994.     FDecisionSource := source;
  1995.     DecisionDataEvent(xeSourceChange);
  1996.   end;
  1997. end;
  1998.  
  1999. { TDimInfoArray }
  2000.  
  2001. constructor tDimInfoArray.Create(ALimit: Integer);
  2002. begin
  2003.   FLimit := ALimit;
  2004.   GetMem(FElements,FLimit*SizeOf(TDimInfo));
  2005.   FDimNames := TStringList.Create;
  2006. end;
  2007.  
  2008. destructor TDimInfoArray.Destroy;
  2009. begin
  2010.   AllXDim.free;
  2011.   FreeMem(FElements);
  2012.   FDimNames.free;
  2013.   FDimNames := nil;
  2014.   inherited;
  2015. end;
  2016.  
  2017. procedure TDimInfoArray.Assign(Value: TDimInfoArray);
  2018. begin
  2019.   if (FLimit <> Value.Flimit) then
  2020.   begin
  2021.     FreeMem(FElements);
  2022.     FElements := nil;
  2023.     FLimit := Value.Flimit;
  2024.     GetMem(FElements,Flimit*SizeOf(TDimInfo));
  2025.   end;
  2026.   CopyMemory(FElements,Value.FElements,FLimit * SizeOf(TDimInfo));
  2027.   FDimNames.assign(Value.FDimNames);
  2028. end;
  2029.  
  2030. function TDimInfoArray.isEqual(Value: TDimInfoArray): Boolean;
  2031. var
  2032.   i: Integer;
  2033.   ptr1, ptr2: pchar;
  2034. begin
  2035.   Result := False;
  2036.   if (FLimit <> Value.FLimit) then Exit;
  2037.   ptr1 := pChar(FElements);
  2038.   ptr2 := pChar(Value.FElements);
  2039.   for i := 0 to (sizeOf(TDimInfo)*FLimit)-1 do
  2040.   begin
  2041.     if (@ptr1 <> @ptr2) then Exit;
  2042.     ptr1 := ptr1 + 1;
  2043.     ptr2 := ptr2 + 1;
  2044.   end;
  2045.   Result := True;
  2046. end;
  2047.  
  2048. function TDimInfoArray.GetGroupIndex(Group: TDimGroup; Index: Integer; bOpen: Boolean): Integer;
  2049. var
  2050.   i: Integer;
  2051. begin
  2052.   for i := 0 to limit-1 do
  2053.   begin
  2054.     if (items[i].iGroup <> Group) then Continue;
  2055.     if bOpen then
  2056.     begin
  2057.       if (items[i].iActiveIndex <> index) then Continue;
  2058.     end
  2059.     else
  2060.     begin
  2061.       if (items[i].iIndex <> index) then Continue;
  2062.     end;
  2063.     Result := i;
  2064.     Exit;
  2065.   end;
  2066.   Result := -1;
  2067. end;
  2068.  
  2069. function TDimInfoArray.GetGroupItem(Group: TDimGroup; Index: Integer; bOpen: Boolean): PDimInfo;
  2070. var
  2071.   i: Integer;
  2072. begin
  2073.   i := GetGroupIndex(Group, Index, bOpen);
  2074.   if (i < 0) then
  2075.     Result := nil
  2076.   else
  2077.     Result := items[i];
  2078. end;
  2079.  
  2080. function TDimInfoArray.GetGroupSize(Group: TDimGroup; bOpen: Boolean): Integer;
  2081. var
  2082.   i: Integer;
  2083. begin
  2084.   Result := 0;
  2085.   for i := 0 to limit-1 do
  2086.   begin
  2087.     if (items[i].iGroup <> Group) then Continue;
  2088.  
  2089.     if bOpen then
  2090.     begin
  2091.       if (items[i].iState <> dmOpen) then Continue;
  2092.     end;
  2093.     Result := Result + 1;
  2094.   end;
  2095. end;
  2096.  
  2097. function TDimInfoArray.GetGroupArray(Group: TDimGroup; bOpen: Boolean): TIArray;
  2098. var
  2099.   i: Integer;
  2100. begin
  2101.   if not assigned(AllXDim) then AllXDim := TIArray.create(0, 0);
  2102.   Result := AllXDim;
  2103.   Result.ReAlloc(0);
  2104.   Result.AutoSize := True;
  2105.   if bOpen then
  2106.   begin
  2107.     for i := 0 to limit-1 do
  2108.     begin
  2109.       if (Items[i].iGroup = Group) and (Items[i].iState = dmOpen) then
  2110.       begin
  2111.         Result[Items[i].iActiveIndex] := i;
  2112.       end;
  2113.     end;
  2114.   end
  2115.   else
  2116.   begin
  2117.     for i := 0 to limit-1 do
  2118.     begin
  2119.       if (items[i].iGroup = Group) then
  2120.         Result[items[i].iIndex]:= i;
  2121.     end;
  2122.   end;
  2123.   Result.autosize := False;
  2124. end;
  2125.  
  2126. function TDimInfoArray.GetItem(Index: Integer): PDimInfo;
  2127. begin
  2128.   if (Index < 0) or (Index >= FLimit) then
  2129.     raise EArrayError.CreateRes(@sOutOfbounds)
  2130.   else
  2131.     Result := @PArrayDimInfo(FElements)^[Index];
  2132. end;
  2133.  
  2134. function TDimInfoArray.Find(Name: string; var pos: Integer): Boolean;
  2135. var
  2136.   i: Integer;
  2137. begin
  2138.   for i := 0 to FDimNames.count-1 do
  2139.   begin
  2140.     if (FDimNames[i] = Name) then
  2141.     begin
  2142.       pos := i;
  2143.       Result := True;
  2144.       Exit;
  2145.     end;
  2146.   end;
  2147.   Result := False;
  2148. end;
  2149.  
  2150. constructor TIArray.Create(ALimit: Integer; aBlocksize: Integer);
  2151. begin
  2152.   if (aBlocksize <= 0) then
  2153.     FBlockSize := defDimSize
  2154.   else
  2155.     FBlockSize := aBlockSize;
  2156.   Alloc(ALimit);
  2157. end;
  2158.  
  2159. destructor TIArray.Destroy;
  2160. begin
  2161.   FreeMem(FElements);
  2162.   inherited;
  2163. end;
  2164.  
  2165. procedure TIArray.Alloc(ALimit: Integer);
  2166. begin
  2167.   FreeMem(FElements);
  2168.   FLimit := ALimit;
  2169.   if (FBlocksize = 1) then
  2170.     FCapacity := ALimit
  2171.   else
  2172.     FCapacity := ((FLimit div FBlocksize) + 1) * FBlocksize;
  2173.   GetMem(FElements,FCapacity * SizeOf(Integer));
  2174. end;
  2175.  
  2176. procedure TIArray.Realloc(ALimit: Integer);
  2177. var
  2178.   L: Integer;
  2179.   P: Pointer;
  2180. begin
  2181.   if (ALimit > FCapacity) or (ALimit < (FCapacity-FBlocksize)) then
  2182.   begin
  2183.     L := Min(FLimit,ALimit);
  2184.     P := FElements;
  2185.     FElements := nil;
  2186.     Alloc(ALimit);
  2187.     CopyMemory(FElements,P,L * SizeOf(Integer));
  2188.     FreeMem(P);
  2189.   end;
  2190.   FLimit := ALimit;
  2191. end;
  2192.  
  2193. procedure TIArray.Assign(Value: TIArray);
  2194. begin
  2195.   if (FLimit <> Value.FLimit) then
  2196.     Alloc(Value.FLimit);
  2197.   CopyMemory(FElements,Value.FElements,FLimit * SizeOf(Integer));
  2198. end;
  2199.  
  2200. function TIArray.GetItem(Index: Integer): Integer;
  2201. begin
  2202.   if (FElements = nil) or (Index < 0) or (Index >= FLimit) then
  2203.     raise EArrayError.CreateRes(@sOutOfbounds);
  2204.   Result := PArrayInt(FElements)^[Index];
  2205. end;
  2206.  
  2207. procedure TIArray.SetItem(Index: Integer; Value: Integer);
  2208. begin
  2209.   if (FElements = nil) or (Index < 0) or (Index >= FLimit) then
  2210.   begin
  2211.     if (FElements <> nil) and FAutoIncr and (Index >= FLimit) then
  2212.       Realloc(Index + 1)
  2213.     else
  2214.       raise EArrayError.CreateRes(@sOutOfbounds);
  2215.   end;
  2216.   PArrayInt(FElements)^[Index] := Value;
  2217. end;
  2218.  
  2219. procedure TIArray.InsertAt(Index: Integer; Value: Integer);
  2220. begin
  2221.   if (Index < 0) or (Index > FLimit) then
  2222.     raise EArrayError.CreateRes(@sOutOfbounds);
  2223.   Realloc(FLimit+1);
  2224.   if (Index+1 < FLimit) then
  2225.     CopyMemory(@PArrayInt(FElements)^[Index+1], @PArrayInt(FElements)^[Index], (FLimit-Index-1) * SizeOf(Integer));
  2226.   SetItem(Index,Value);
  2227. end;
  2228.  
  2229. function TIArray.RemoveItem(Index: Integer): Integer;
  2230. begin
  2231.   if (Index < 0) or (Index+1 > FLimit) then
  2232.     raise EArrayError.CreateRes(@sOutOfbounds);
  2233.   Result := GetItem(Index);
  2234.   if ((Index + 1) < FLimit) then
  2235.     CopyMemory(@PArrayInt(FElements)^[Index], @PArrayInt(FElements)^[Index+1], (FLimit-Index-1) * SizeOf(Integer));
  2236.   Realloc(FLimit-1);
  2237. end;
  2238.  
  2239. function TDecisionSource.GetExampleRepCount(dimGroup: TDimGroup; level: Integer): Integer;
  2240. var
  2241.   max, times: Integer;
  2242.   subs: Boolean;
  2243.   Elements: array[0..4] of Integer;
  2244. begin
  2245.   Elements[0] := 2;
  2246.   Elements[1] := 3;
  2247.   Elements[2] := 4;
  2248.   Elements[3] := 3;
  2249.   Elements[4] := 2;
  2250.   with FData do
  2251.   begin
  2252.     if (dimGroup = dgRow) then
  2253.     begin
  2254.       max := fActiveRows;
  2255.       subs := FrowSubs;
  2256.     end
  2257.     else
  2258.     begin
  2259.       max := fActiveCols;
  2260.       subs := FcolSubs;
  2261.     end;
  2262.     if (level >= max) then Result := 1
  2263.     else
  2264.     begin
  2265.       times := Elements[GetActiveDim(dimGroup, level,True)];
  2266.       Result := GetExampleRepCount(dimGroup, level+1)*times;
  2267.       if subs then Result := Result + 1;
  2268.     end;
  2269.   end;
  2270. end;
  2271.  
  2272. { Row/Col oriented Access Functions }
  2273.  
  2274. function TDecisionSource.GetActiveDim(dimGroup: TDimGroup; index: Integer; bOpen: Boolean): Integer;
  2275. begin
  2276.   Result := FData.DimInfo.GetGroupIndex(dimGroup, Index, bOpen);
  2277. end;
  2278.  
  2279. procedure TDecisionSource.DrillDimIndex(dimGroup: TDimGroup; Index: Integer; ValueIndex: Integer; bOpen: Boolean);
  2280. var
  2281.   iDim: Integer;
  2282. begin
  2283.   with FData do
  2284.   begin
  2285.     iDim := GetActiveDim(dimGroup, Index, bOpen);
  2286.     if (iDim >= 0) then DrillValue(iDim, ValueIndex);
  2287.   end;
  2288. end;
  2289.  
  2290. procedure TDecisionSource.MoveDimIndexes(SdimGroup, DdimGroup: TDimGroup; SIndex, DIndex: Integer; bOpen: Boolean);
  2291. var
  2292.   Index, i: Integer;
  2293.   iDim, sDim, dDim: Integer;
  2294.   AllXDim: TIArray;
  2295. begin
  2296.   with FData do
  2297.   begin
  2298.     if (SdimGroup = DdimGroup) and (SIndex = DIndex) then Exit;
  2299.     sDim := GetActiveDim(SdimGroup, sIndex, bOpen);
  2300.     dDim := GetActiveDim(DdimGroup, dIndex, bOpen);
  2301.     BeginChange;
  2302.     AllXDim := DimInfo.GetGroupArray(SdimGroup, False);
  2303.     Index := DimInfo[sDim].iIndex;
  2304.     for i := 0 to AllXDim.limit-1 do
  2305.     begin
  2306.       iDim := AllXDim[i];
  2307.       if (DimInfo[iDim].iIndex > index) then
  2308.         DimInfo[iDim].iIndex := DimInfo[iDim].iIndex - 1;
  2309.     end;
  2310.     AllXDim := DimInfo.GetGroupArray(DdimGroup, False);
  2311.     if (dDim < 0) or (DIndex >= AllXDim.Limit) then
  2312.       Index := AllXDim.Limit
  2313.     else
  2314.       index := DimInfo[dDim].iIndex;
  2315.     for i := 0 to AllxDim.limit-1 do
  2316.     begin
  2317.       iDim := AllXDim[i];
  2318.       if (DimInfo[iDim].iIndex >= index) then
  2319.         DimInfo[iDim].iIndex := DimInfo[iDim].iIndex + 1;
  2320.     end;
  2321.     DimInfo[sDim].iGroup := DdimGroup;
  2322.     DimInfo[sDim].iIndex := Index;
  2323.     EnforceConstraints(DdimGroup, Index);
  2324.     if (DdimGroup <> SdimGroup) then
  2325.       EnforceConstraints(SdimGroup, -1);
  2326.     EndChange(xePivot);
  2327.   end;
  2328. end;
  2329.  
  2330. procedure TDecisionSource.SwapDimIndexes(SdimGroup, DdimGroup: TDimGroup; SIndex, DIndex: Integer; bOpen: Boolean);
  2331. var
  2332.   Index: Integer;
  2333.   sDim, dDim: Integer;
  2334. begin
  2335.   with FData do
  2336.   begin
  2337.     if (SdimGroup = DdimGroup) and (SIndex = DIndex) then Exit;
  2338.     sDim := GetActiveDim(SdimGroup, sIndex, bOpen);
  2339.     dDim := GetActiveDim(DdimGroup, dIndex, bOpen);
  2340.     BeginChange;
  2341.     DimInfo[sDim].iGroup := DdimGroup;
  2342.     index := DimInfo[sDim].iIndex;
  2343.     DimInfo[sDim].iIndex := DimInfo[dDim].iIndex;
  2344.     DimInfo[dDim].iGroup := SdimGroup;
  2345.     DimInfo[dDim].iIndex := index;
  2346.     EnforceConstraints(DdimGroup, Index);
  2347.     if (DdimGroup <> SdimGroup) then
  2348.       EnforceConstraints(SdimGroup, -1);
  2349.     EndChange(xePivot);
  2350.   end;
  2351. end;
  2352.  
  2353. procedure TDecisionSource.DrillValue(iDim: Integer; ValueIndex: Integer);
  2354. var
  2355.   PreserveIndex: Integer;
  2356. begin
  2357.   assert(ValueIndex<GetDimensionMemberCount(iDim), 'Illegal value selected');
  2358.   if (iDim >= 0) then
  2359.     with FData do
  2360.     begin
  2361.       if (DimInfo[iDim].istate = dmPaged) then Exit;
  2362.       BeginChange;
  2363.       DimInfo[iDim].IValue := ValueIndex;
  2364.       if (DimInfo[iDim].Istate <> dmPaged) then
  2365.         DimInfo[iDim].IState := dmDrilled;
  2366.       PreserveIndex := DimInfo[iDim].IIndex;
  2367.       EnforceConstraints(DimInfo[iDim].IGroup, PreserveIndex);
  2368.       EndChange(xePivot);
  2369.     end;
  2370. end;
  2371.  
  2372. constructor TPivotState.Create;
  2373. begin
  2374.   DimInfo := TDimInfoArray.Create(0);
  2375.   FSums := 0;
  2376.   FDims := 0;
  2377.   FCurrentSum := 0;
  2378.   FRowSparse := False;
  2379.   FRowSubs := True;
  2380.   FColSparse := False;
  2381.   FColSubs := True;
  2382. end;
  2383.  
  2384. destructor TPivotState.Destroy;
  2385. begin
  2386.   DimInfo.free;
  2387.   DimInfo := nil;
  2388.   inherited;
  2389. end;
  2390.  
  2391. procedure TPivotState.Assign(Value: TPivotState);
  2392. begin
  2393.   FDims := Value.FDims;
  2394.   FSums := Value.FSums;
  2395.   FCurrentSum := Value.FCurrentSum;
  2396.   FRowSparse := Value.FRowSparse;
  2397.   FColSparse := Value.FColSparse;
  2398.   FRowSubs := Value.FRowSubs;
  2399.   FColSubs := Value.FColSubs;
  2400.   DimInfo.Assign(Value.DimInfo);
  2401. end;
  2402.  
  2403. function TPivotState.IsEqual(Value: TPivotState): Boolean;
  2404. begin
  2405.   Result := False;
  2406.   if (FDims <> Value.FDims) then Exit;
  2407.   if (FSums <> Value.FSums) then Exit;
  2408.   if (FCurrentSum <> Value.FCurrentSum) then Exit;
  2409.   if (FRowSparse <> Value.FRowSparse) then Exit;
  2410.   if (FColSparse <> Value.FColSparse) then Exit;
  2411.   if (FRowSubs <> Value.FRowSubs) then Exit;
  2412.   if (FColSubs <> Value.FColSubs) then Exit;
  2413.   Result := DimInfo.isEqual(Value.DimInfo);
  2414. end;
  2415.  
  2416. end.
  2417.  
  2418.